/*
 * Yabumi, a 2d scrolling shoot-em-up game.
 * Copyright (C) 2003 Gemma Teruaki <terugen@yabumi.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 */

#include <math.h>
#include "../util.h"
#include "../taskmanager.h"
#include "hitcircle.h"
#include "homing.h"
#include "player.h"
#include "enemy.h"
#include "musashi.h"

extern _list_header *active_task_list_header, *expired_task_list_header;
_list_header hitcircle_list_header;

void Hitcircle_Init()
{
  Create_list(&hitcircle_list_header);
}

void Hitcircle_Free()
{
  Free_list(&hitcircle_list_header);
}

_Hitcircle *Hitcircle_Create(void *socket, _client_type client_type, \
			     int radius, _radar_reaction radar_reaction, \
			     int cr, int cangle)
{
  _list_item *list_item;
  list_item = (_list_item *)pmalloc(sizeof(_list_item));
  Add_item_last(&hitcircle_list_header, list_item);

  _Hitcircle *hitcircle = &list_item->data.Hitcircle;
  hitcircle->root = list_item;

  _Player *player;
  _Enemy *enemy;
  _Musashi *musashi;

  hitcircle->client_type = client_type;
  hitcircle->radius = radius;
  hitcircle->radar_reaction = radar_reaction;
  hitcircle->cr = cr;
  hitcircle->cangle = cangle;
  hitcircle->was_hit = __hit_no;

  switch (hitcircle->client_type) {
  case __hitcircle_player:
    player = (_Player *)socket;
    hitcircle->x = player->x;
    hitcircle->y = player->y;
    break;
  case __hitcircle_enemy:
    enemy = (_Enemy *)socket;
    hitcircle->x = enemy->x;
    hitcircle->y = enemy->y;
    break;
  case __hitcircle_musashi:
    musashi = (_Musashi *)socket;
    hitcircle->x = musashi->x + hitcircle->cr * cos((hitcircle->cangle + musashi->angle) * RM_PI);
    hitcircle->y = musashi->y + hitcircle->cr * sin((hitcircle->cangle + musashi->angle) * RM_PI);
    hitcircle->x = musashi->x;
    hitcircle->y = musashi->y;
    break;
  };
  return hitcircle;
}

task Hitcircle_Add(_option *optv)
{
  _Hitcircle *hitcircle;
  hitcircle = (_Hitcircle *)optv->socket[0];

  _Player *player;
  _Enemy *enemy;
  _Musashi *musashi;

  switch (hitcircle->client_type) {
  case __hitcircle_player:
    player = (_Player *)optv->socket[1];
    Task_Add(Hitcircle_Move, hitcircle, player, INFINITY_COUNT);
    break;
  case __hitcircle_enemy:
    enemy = (_Enemy *)optv->socket[1];
    Task_Add(Hitcircle_Move, hitcircle, enemy, INFINITY_COUNT);
    break;
  case __hitcircle_musashi:
    musashi = (_Musashi *)optv->socket[1];
    Task_Add(Hitcircle_Move, hitcircle, musashi, INFINITY_COUNT);
    break;
  };
}

task Hitcircle_Move(_option *optv)
{
  _Hitcircle *hitcircle;
  hitcircle = (_Hitcircle *)optv->socket[0];

  if (optv->count == ONETIME_COUNT) {
    optv->count = KILL_COUNT;
    Task_Add(Hitcircle_Kill, hitcircle, NULL, ONETIME_COUNT);
    return;
  };

  _Player *player;
  _Enemy *enemy;
  _Musashi *musashi;

  switch (hitcircle->client_type) {
  case __hitcircle_player:
    player = (_Player *)optv->socket[1];
    hitcircle->x = player->x;
    hitcircle->y = player->y;
    if (hitcircle->was_hit != __hit_no) {
      player->tasks.was_hit = hitcircle->was_hit;
      hitcircle->was_hit = __hit_no;
    };
    break;
  case __hitcircle_enemy:
    enemy = (_Enemy *)optv->socket[1];
    hitcircle->x = enemy->x;
    hitcircle->y = enemy->y;
    if (hitcircle->was_hit != __hit_no) {
      enemy->tasks.was_hit = hitcircle->was_hit;
      hitcircle->was_hit = __hit_no;
    };
    break;
  case __hitcircle_musashi:
    musashi = (_Musashi *)optv->socket[1];
    hitcircle->x = musashi->x + \
      hitcircle->cr * cos((hitcircle->cangle + musashi->angle) * RM_PI);
    hitcircle->y = musashi->y + \
      hitcircle->cr * sin((hitcircle->cangle + musashi->angle) * RM_PI);
    if (hitcircle->was_hit != __hit_no) {
      musashi->tasks.was_hit = hitcircle->was_hit;
      hitcircle->was_hit = __hit_no;
    };
    break;
  };
};

task Hitcircle_Kill(_option *optv)
{
  _Hitcircle *hitcircle;
  hitcircle = (_Hitcircle *)optv->socket[0];

  int i;
  _list_item *list_item;
  _task_item *task_item;

  if (optv->count == ONETIME_COUNT) {
    list_item = active_task_list_header->next->next;
    while (list_item != active_task_list_header->prev) {
      task_item = &list_item->data.task_item;
      for (i = 0; i < MAX_SOCKET; i++) {
	if (task_item->option.socket[i] == hitcircle) {
	  if (task_item->fp == Homing_Move) {
	    task_item->option.count = ONETIME_COUNT;
	  } else {
	    task_item->option.count = KILL_COUNT;
	  };
	};
      };
      list_item = list_item->next;
    };
    list_item = expired_task_list_header->next->next;
    while (list_item != expired_task_list_header->prev) {
      task_item = &list_item->data.task_item;
      for (i = 0; i < MAX_SOCKET; i++) {
	if (task_item->option.socket[i] == hitcircle) {
	  if (task_item->fp == Homing_Move) {
	    task_item->option.count = ONETIME_COUNT;
	  } else {
	    task_item->option.count = KILL_COUNT;
	  };
	};
      };
      list_item = list_item->next;
    };
    Kill_item(&hitcircle_list_header, (_list_item *)hitcircle->root);
    pfree(hitcircle->root);
  };
}

